Cecil B. Moore Ave

Overall Corridor Analysis

Overview

The Cecil B. Moore Ave transit corridor runs along Cecil B Moore Av , 17th St , 16th St , Broad St , 12th St , and 11th St between 17th St and 8th St. The corridor serves the routes 23, 16, 4, 701, 3, and 2. There are 25 total bus stops along the corridor. The corridor directly served 4885 riders per day in 2019.

Weekday Ridership

The Cecil B. Moore Ave corridor moves 4885 transit passengers per day. The peak hour for transit passenger movement on the corridor is 15. At the peak hour, the corridor serves 492 riders.

Speed and Reliability

Speed and reliability are two of the most important aspects governing how attractive transit is to the customer.

There is, however, an important distinction between transit speed and transit reliability:

  • Speed is how fast the vehicle is moving through the corridor.
  • Reliability is how consistent those speeds are, throughout a day or another period of time.

Oftentimes, qualitative research on transit finds that riders remember their worst trip much more vividly than their average (or even their best) trips. This is where reliability is key - providing customers with a consistent trip time is just as important as a fast trip time, because when they budget time for future trips, they have to be reasonably sure that the time budgeted will represent the majority of potential travel time outcomes.

Bus Speeds

Reliability

## [[1]]

## 
## [[2]]

Travel Times

Corridor-level travel time is simply the amount of time it takes the bus to travel from one end of the corridor to another. In this case, it is show separated by route and by direction and is averaged for each hour.

Service Hours

Service hours are a measure of how much transit is operated on the corridor. It is simply the sum of all of the runtime on the corridor over a period of time. Service hours is a product of how much transit is provide, but it is also a product of the speed of operations on a corridor. Transit productivity is often measured in terms of service hours because it is the most direct input into the cost of running the service.

Sub-Corridor Analysis

17th to Broad Analytics

Subcorridor Daily Analytics

route_id daily_ridership trips routes_served service_hours riders_per_hour on_off dwell_observed_mean dwell_predicted_mean dwell_hybrid_mean dwell_per_onoff onoff_per_trip onoff_per_tripstop avg_segment_speed avg_speed_10_pct avg_speed_25_pct avg_speed_75_pct avg_speed_90_pct
3 4,805 172 3 9.2 523 3,032 75.1 53.3 75.1 0.3 17.6 4.4 6 4.7 5.3 6.5 7.4
Total 4,805 172 3 9.2 523 3,032 75.1 53.3 75.1 0.2 17.6 4.4 6 4.7 5.3 6.5 7.4

Weekday Ridership

Speed and Reliability

Speed
Reliability
## [[1]]

## 
## [[2]]

End-to-End Travel Time

## NULL

Broad to 9th Analytics

Subcorridor Daily Analytics

route_id daily_ridership trips routes_served service_hours riders_per_hour on_off dwell_observed_mean dwell_predicted_mean dwell_hybrid_mean dwell_per_onoff onoff_per_trip onoff_per_tripstop avg_segment_speed avg_speed_10_pct avg_speed_25_pct avg_speed_75_pct avg_speed_90_pct
3 3,003 172 3 6.3 478.4 722 30.8 26.5 30.8 0.2 4.2 0.7 10.7 9 9.5 11.5 13.1
Total 3,003 172 3 6.3 478.4 722 30.8 26.5 30.8 0.1 4.2 0.7 10.7 9 9.5 11.5 13.1

Weekday Ridership

Speed and Reliability

Speed
Reliability
## [[1]]

## 
## [[2]]

End-to-End Travel Time

## NULL

Sub-Corridor Comparison

plot_speed_corridor_comparison(comparison_df)

Stop Level Analysis

Stop Level Map

label_stops <- function(dat) {
  
  daily <- dat$daily_stop_analytics
  hourly <- dat$stop_route_hourly_analytics
    
  paste0( "Stop:", daily[[i]]$stop_name , "<br>",
          "Stop ID: ", daily$stop_id, "<br>",
          "Daily Boards", daily$total_ons, "<br>",
          "Daily Leaves", daily$total_ons, "<br>",
          "Maximum Hourly Dwell: ", hourly$avg_dwell_hybrid)
  
}

# map of stops that on the corridor
leaflet() %>%
  setView(lng = mean(full_stop_data$daily_stop_analytics[[1]]$stop_lon, na.rm=TRUE), 
          lat = mean(full_stop_data$daily_stop_analytics[[1]]$stop_lat, na.rm=TRUE), zoom = 14) %>% 
  addProviderTiles(providers$Stamen.Toner) %>% 
  addCircleMarkers(full_stop_data$daily_stop_analytics[[1]], 
                   lat = full_stop_data$daily_stop_analytics[[1]]$stop_lat, 
                   lng = full_stop_data$daily_stop_analytics[[1]]$stop_lon, 
                   radius = log((full_stop_data$daily_stop_analytics[[1]]$total_ons + 
                               (full_stop_data$daily_stop_analytics[[1]]$total_offs)))*2.55, 
                   color = "blue", 
                   popup = popupTable(full_stop_data$daily_stop_analytics[[1]]))
# also add chart/table of global averages for context of subcorridors

Daily Analytics by Stop Table

table_2 <- full_stop_data$daily_stop_analytics[[1]] %>% select(-c(avg_speed, stop_lat, stop_lon))
 
# kable(table_2, booktabs = TRUE, align = 'c',format.args = list(big.mark = ","),digits=1) %>%
#   kable_styling(latex_options = "scale_down")  %>%
#   row_spec(dim(table_1)[1], bold = T) %>% # format last row
#   column_spec(1, italic = T) %>%  # format first column
#   scroll_box(width = "100%", height = "300px")

reactable(table_2,
    filterable = TRUE,
    resizable = TRUE,
    columns = list(
    # route_id = colDef(
    #   sticky = "left",
    #   headerStyle = list(borderRight = "1px solid #eee")
    # ),
    # direction_id = colDef(
    #   sticky = "left",
    #   headerStyle = list(borderRight = "1px solid #eee")
    # ),
    # stop_id = colDef(
    #   sticky = "left",
    #   headerStyle = list(borderRight = "1px solid #eee")
    # ),
    # stop_name = colDef(
    #   sticky = "left",
    #   # Add a right border style to visually distinguish the sticky column
    #   style = list(borderRight = "1px solid #eee"),
    #   headerStyle = list(borderRight = "1px solid #eee")
    # ),
      #total_trips = colDef(aggregate = "max"),
      #avg_headway = colDef(aggregate = "mean", format = colFormat(digits = 1)),
      total_ons = colDef(aggregate = "sum", format = colFormat(digits = 0)),
      total_offs = colDef(aggregate = "sum", format = colFormat(digits = 0)),
      avg_load = colDef(format = colFormat(digits = 0)),
      avg_dwell_observed = colDef(format = colFormat(digits = 2)),
      avg_dwell_estimated = colDef(format = colFormat(digits = 2)),
      avg_dwell_hybrid = colDef(format = colFormat(digits = 2)),
      avg_dwell_per_pass_hybrid = colDef(format = colFormat(digits = 2))
    )
)

Daily Analytics by Stop/Route Table

  • User input to add/subtracts routes - i.e. pull from the route level data?
table_3 <- full_stop_data$stop_route_analytics[[1]] %>% select(route_id, direction_id, everything()) %>% select(-c(routes, avg_speed, stop_lat, stop_lon)) %>%  group_by(route_id, direction_id) %>% dplyr::arrange(route_id, direction_id, stop_lon)

reactable(
  table_3,
  #filterable = TRUE,
  groupBy = c("route_id", "direction_id"),
  pagination = FALSE, 
  resizable = TRUE,
  height = 500,
  columns = list(
    # route_id = colDef(
    #   sticky = "left",
    #   headerStyle = list(borderRight = "1px solid #eee")
    # ),
    # direction_id = colDef(
    #   sticky = "left",
    #   headerStyle = list(borderRight = "1px solid #eee")
    # ),
    # stop_id = colDef(
    #   sticky = "left",
    #   headerStyle = list(borderRight = "1px solid #eee")
    # ),
    # stop_name = colDef(
    #   sticky = "left",
    #   # Add a right border style to visually distinguish the sticky column
    #   style = list(borderRight = "1px solid #eee"),
    #   headerStyle = list(borderRight = "1px solid #eee")
    # ),
    total_trips = colDef(aggregate = "max"),
    avg_headway = colDef(aggregate = "mean", format = colFormat(digits = 1)),
    total_ons = colDef(aggregate = "sum", format = colFormat(digits = 1)),
    total_offs = colDef(aggregate = "sum", format = colFormat(digits = 1)),
    avg_load = colDef(aggregate = "mean", format = colFormat(digits = 1)),
    avg_dwell_observed = colDef(aggregate = "mean", format = colFormat(digits = 1)),
    avg_dwell_estimated = colDef(aggregate = "mean", format = colFormat(digits = 1)),
    avg_dwell_hybrid = colDef(aggregate = "mean", format = colFormat(digits = 1)),
    avg_dwell_per_pass_hybrid = colDef(aggregate = "mean", format = colFormat(digits = 1))
  ),
  defaultColDef = colDef(minWidth = 150)
)

Stop Profile by Route/Direction